POC
===

Si tratta di una cosidetta "Proof Of Concept" su come implementare una Api di tipo Restful con Spring Boot e Hateoas.
È un progetto di auto formazione; c'è molto più codice di quello che serve nella pratica ma serve a esploarare le varie tecniche.

LINKS DI RIFERIMENTO
====================

01. https://dev.to/markbdsouza/paginationwith-hateoas-filtering-sorting-with-spring-boot-and-jpa-1mpp
02. https://codeburst.io/spring-boot-rest-microservices-best-practices-2a6e50797115
03. https://www.ixonae.com/setup-http-basic-authentication-with-java-spring-boot-rest-api/
04. https://blog.piinalpin.com/2022/04/searching-and-filtering-using-jpa-specification/
05. https://riptutorial.com/spring-boot/example/21856/dev-and-prod-environment-using-different-datasources
06. https://www.baeldung.com/sql-logging-spring-boot
07. https://medium.com/codestorm/custom-json-response-with-responseentity-in-spring-boot-b09e87ab1f0a
08. https://dzone.com/articles/realistic-test-data-generation-for-java-apps
09. https://www.baeldung.com/spring-data-jpa-dynamicupdate

DA NOTARE
=========

Non sono presenti Unit Tests ma è presente la collezione Postman usata per fare le verifiche.

Sono implementati 5 versioni per ottenere la lista della risorsa:
v0:        lista completa
v1:        lista filtro singolo
v2:        lista filtro singolo e paginata
v3:        lista filtro singolo, ordinamento singolo e paginata
v4:        lista filtro singolo, ordinamento singolo e paginata con response Hateos
v4/search: lista filtro multiplo, ordinamento multiplo e paginata con response Hateos

La versione v0:
- usa annotazione @Query
- torna un List<Food>
La versione v1:
- usa annotazione @Query
- accetta UNA condizione di filtro
- torna un List<Food>
Le versioni v2:
- usa Jpa Specification
- accetta UNA condizione di filtro
- torna un Paged<Food>
La versione v3:
- usa Jpa Specification
- accetta UNA condizione di filtro
- accetta UNA condizione di ordinamento
- torna un Paged<Food>
La versione v4:
- usa Jpa Specification
- accetta UNA condizione di filtro
- accetta UNA condizione di ordinamento
- torna un PagedModel<FoodModel>
La versione v4/seach:
- usa Jpa Specification
- accetta MULTIPLE condizioni di filtro
- accetta MULTIPLE condizioni ordinamento
- accetta un payload di tipo JSON
- torna un PagedModel<FoodModel>

Esempi di Payload:
Senza filtri, senza ordinamento, senza paginatura
{
    "filters": [],
    "sorts": [],
    "page": null,
    "size": null
}
Un filtro in EQUAL, un ordinamento, senza paginatura
{
    "filters": [
        {
            "key": "name",
            "operator": "EQUAL",
            "field_type": "STRING",
            "value": "CentOS"
        }
    ],
    "sorts": [
        {
            "key": "releaseDate",
            "direction": "ASC"
        }
    ],
    "page": null,
    "size": null
}
Un filtro in BETWEEN, senza ordinamento, senza paginatura
{
    "filters": [
        {
            "key": "releaseDate",
            "operator": "BETWEEN",
            "field_type": "DATE",
            "value": "01-03-2022 00:00:00",
            "value_to": "11-03-2022 23:59:59"
        }
    ],
    "sorts": [],
    "page": null,
    "size": null
}

Per vedere gli operatori supportati vedere enum com.example.poc.query.Operator
Per la struttura del filtro vedere classe com.example.poc.query.FilterRequest
Per la struttura dell'ordinamento vedere classe com.example.poc.query.SortRequest

Esiste un GeneralExceptionHandler che si occupa di gestire:
- gli errori dovuti a BAD_REQUEST
- gli errori dovuti alle validazioni dei constraint

Esiste un CustomAuthenticationEntryPoint che gestisce:
- gli errori di Autenticazione (http 401)
- gli errori di Autorizzazione (http 403)
- gli errori per risorsa non trovata (http 404)
- gli errori generici (http 500)

Sono implementati 2 Dto, uno per Insert (POST) e Update completo (PUT), uno per Update parziale (PATCH).
Questo per i seguenti motivi:
- volevo fornire entrambi i casi
- volevo eseguire i controlli di integrità dei dati prima di provare a persisterli
Riassumendo:
- Food ha @Column con in constraints per il db
- FoodDto ha @NotBlank e @Length
- FoddDtoPatch ha @Length
È una maniera più prolissa di quella "standard" ma la preferisco.

Food usa @DynamicUpdate per ottimizzare sql generato per update parziali